package com.meshnetics.gb.stack.mac.primitives;

import com.meshnetics.gb.stack.core.event.StackEventType;
import com.meshnetics.gb.stack.core.event.StackIndication;
import com.meshnetics.gb.stack.core.layer.StackLayer;
import com.meshnetics.gb.stack.mac.RadioMACStackLayer;
import com.meshnetics.gb.type.impl.ByteUtils;
import com.meshnetics.gb.type.impl.zcl.*;

import java.nio.ByteBuffer;

/**
 * WRITE DESCRIPTION HERE
 *
 * @author AKovylin
 */
public class MACOrphanIndication extends StackIndication {
    public static final byte CODE = 0x52;

    private final UInt orphanAddress;
    private final Bitmap secAndAcl;

    public MACOrphanIndication(ByteBuffer bb, RadioMACStackLayer layer) {
        super("macOrphanIndication", StackEventType.LME_TYPE, null, layer);
        ByteUtils.ensureNotNull(bb);
        ByteUtils.ensureCapacity(bb, 9);
        this.orphanAddress = (UInt) TypeUInt.UINT_64.deserialize(bb);
        this.secAndAcl = (Bitmap) TypeBitmap.BITMAP_8.deserialize(bb);
        if (bb.remaining() > 0) {
            throw new IllegalArgumentException("unexpected content of ByteBuffer, " + bb.remaining() + " bytes left");
        }
    }

    public MACOrphanIndication(long orphanAddress, boolean securityUse, int aclEntry) {
        this(orphanAddress, securityUse, (byte) (aclEntry & 0xff));
    }

    public MACOrphanIndication(long orphanAddress, boolean securityUse, byte aclEntry) {
        this(new Long(orphanAddress), Boolean.valueOf(securityUse), new Byte(aclEntry));
    }

    public MACOrphanIndication(Long orphanAddress, Boolean securityUse, Byte aclEntry) {
        this(orphanAddress, securityUse, aclEntry, null);
    }

    public MACOrphanIndication(Long orphanAddress, Boolean securityUse, Byte aclEntry, StackLayer sourceLayer) {
        this((UInt) TypeUInt.UINT_64.fromObject(orphanAddress),
                createBitmapSecAndAcl(securityUse.booleanValue(), aclEntry.intValue()), sourceLayer);
    }

    private static Bitmap createBitmapSecAndAcl(boolean secUse, int aclEntry) {
        if (aclEntry < 0 || aclEntry > 8) {
            throw new IllegalArgumentException("invalid aclEntry, must be in range 0-8");
        }
        BitmapEditor be = new BitmapEditor(TypeBitmap.BITMAP_8);
        be.setBit(0, secUse);
        be.setBits(1, 5, aclEntry);
        return be.create();
    }

    public MACOrphanIndication(UInt orphanAddress, Bitmap secAndAcl) {
        this(orphanAddress, secAndAcl, null);
    }

    public MACOrphanIndication(UInt orphanAddress, Bitmap secAndAcl, StackLayer source) {
        super("macOrphanIndication", StackEventType.LME_TYPE, null, source);
        if (orphanAddress == null) {
            throw new NullPointerException("orphanAddress is null");
        }
        if (secAndAcl == null) {
            throw new NullPointerException("secAndAcl is null");
        }
        this.orphanAddress = orphanAddress.convert(TypeUInt.UINT_64);
        this.secAndAcl = secAndAcl;
        if (secAndAcl.getBits(5, 8) != 0) {
            throw new IllegalArgumentException("bits 5-7 of secAndAcl are reserved and should be all zeroes");
        }
    }

    public UInt getOrphanAddressType() {
        return orphanAddress;
    }

    public Long getOrphanAddress() {
        return (Long) orphanAddress.toObject();
    }

    public Bitmap getSecAndAclType() {
        return secAndAcl;
    }

    public boolean isSecurityUse() {
        return secAndAcl.getBit(0);
    }

    public int getAclEntry() {
        return secAndAcl.getBits(1, 5);
    }

    public String toString() {
        return getName() + '(' + orphanAddress + ',' + secAndAcl + ')';
    }
}
